package Utils.data;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 处理字符串的工具类
 *
 * @author d11yu
 */
public class StringUtils {

    //region Regular Expression
    private static Pattern PATTERN = null;

    /**
     * 获取正则表达式匹配结果的二维数组，如果未匹配到，则返回null。
     *
     * @param str0  待处理字符串
     * @param regex 正则表达式
     * @return
     */
    public static String[][] getMatches(String str0, String regex) {
        return getMatches(str0, regex, new int[]{-1});
    }

    /**
     * 判断字符串是否匹配正则表达式
     *
     * @param str0  待处理字符串
     * @param regex 正则表达式
     * @return
     */
    public static Boolean isMatch(String str0, String regex) {
        return getMatcher(str0, regex).find();
    }

    /**
     * 获取正则表达式匹配结果的二维数组，如果未匹配到，则返回null。
     *
     * @param str0     待处理字符串
     * @param regex    正则表达式
     * @param groupIDs 分组ID数组（0-based，0表示匹配完整的正则表达式，1表示第一分组，依此类推），默认为-1，即匹配所有group。
     * @return 返回二维数组
     */
    public static String[][] getMatches(String str0, String regex, int[] groupIDs) {
        return getMatches(str0, regex, MatchMode.find, groupIDs);
    }

    /**
     * 获取正则表达式匹配结果的二维数组，如果未匹配到，则返回null。
     *
     * @param str0     待处理字符串
     * @param regex    正则表达式
     * @param mode     匹配模式，默认为find模式，非贪婪模式需要用matches模式。
     * @param groupIDs 分组ID数组（0-based，0表示匹配完整的正则表达式，1表示第一分组，依此类推），默认为-1，即匹配所有group。
     * @return 返回二维数组
     */
    public static String[][] getMatches(String str0, String regex, MatchMode mode, int[] groupIDs) {
        return transposeMatches(getMatchesList(str0, regex, mode, groupIDs));
    }

    /**
     * 匹配第一个匹配项，如果未匹配到，则返回null。
     *
     * @param str0
     * @param regex
     * @return 如果未匹配到，则返回null。
     */
    public static String getFirstMatch(String str0, String regex) {
        String[][] matches = StringUtils.getMatches(str0, regex);
        if (matches == null) {
            return null;
        }
        return matches[0][0];
    }

    /**
     * 获取正则表达式匹配结果的二维数组，如果未匹配到，则返回null。
     *
     * @param str0  待处理字符串
     * @param regex 正则表达式
     * @return 返回二维数组
     */
    public static List<String[]> getMatchesList(String str0,
                                                String regex
    ) {
        return getMatchesList(str0, regex, MatchMode.find, new int[]{-1});
    }

    /**
     * 获取正则表达式匹配结果的二维数组，如果未匹配到，则返回null。
     *
     * @param str0     待处理字符串
     * @param regex    正则表达式
     * @param groupIDs 分组ID数组（1-based），默认为-1，即匹配所有group。
     * @return 返回二维数组
     */
    public static List<String[]> getMatchesList(String str0,
                                                String regex,
                                                int[] groupIDs
    ) {
        return getMatchesList(str0, regex, MatchMode.find, groupIDs);
    }

    /**
     * 获取正则表达式匹配结果的二维数组，如果未匹配到，则返回null。
     *
     * @param str0     待处理字符串
     * @param regex    正则表达式
     * @param mode     匹配模式，默认为find模式，非贪婪匹配需要使用matches模式。
     * @param groupIDs 分组ID数组（1-based），默认为-1，即匹配所有group。
     * @return 返回二维数组
     */
    public static List<String[]> getMatchesList(String str0,
                                                String regex,
                                                MatchMode mode,
                                                int[] groupIDs
    ) {
        Matcher matcher = getMatcher(str0, regex);
        List<String[]> res = new ArrayList<>();
        switch (mode) {
            case find:
                while (matcher.find()) {
                    String[] item = null;
                    if (Arrays.equals(groupIDs, new int[]{-1})) {
                        // 匹配所有group
                        item = new String[matcher.groupCount() + 1];
                        for (int i = 0; i <= matcher.groupCount(); i++) {
                            item[i] = matcher.group(i);
                        }
                    } else {
                        // 获取groupIDs中小于matcher.groupCount() + 1的元素
                        int[] indexes = Arrays.stream(groupIDs).filter(x -> x < matcher.groupCount() + 1).toArray();
                        item = new String[indexes.length];
                        for (int i = 0; i < indexes.length; i++) {
                            item[i] = matcher.group(groupIDs[i]);
                        }
                    }
                    res.add(item);
                }
                break;
            case matches:
                matcher.matches();
                String[] item = null;
                if (Arrays.equals(groupIDs, new int[]{-1})) {
                    // 匹配所有group
                    item = new String[matcher.groupCount() + 1];
                    for (int i = 0; i <= matcher.groupCount(); i++) {
                        item[i] = matcher.group(i);
                    }
                } else {
                    // 获取groupIDs中小于matcher.groupCount() + 1的元素
                    int[] indexes = Arrays.stream(groupIDs).filter(x -> x < matcher.groupCount() + 1).toArray();
                    item = new String[indexes.length];
                    for (int i = 0; i < indexes.length; i++) {
                        item[i] = matcher.group(groupIDs[i]);
                    }
                }
                res.add(item);
                break;
            default:
                break;
        }
        if (res.size() == 0) {
            return null;
        } else {
            return res;
        }
    }

    /**
     * Match模式：find、matches
     */
    public enum MatchMode {
        /**
         * find模式
         */
        find,

        /**
         * matches模式
         */
        matches,
    }

    /**
     * 将List<String[]> matches转置为二维数组。
     *
     * @param matches
     * @return
     */
    private static String[][] transposeMatches(List<String[]> matches) {
        if (matches == null) {
            return null;
        }
        // 获取最大列数
        int maxColNum = matches.stream().map(p -> p.length).collect(Collectors.toList()).stream().max(Integer::compare).get();
        String[][] res = new String[maxColNum][matches.size()];
        for (int i = 0; i < res.length; i++) {
            for (int j = 0; j < matches.size(); j++) {
                res[i][j] = matches.get(j)[i];
            }
        }
        return res;
    }

    /**
     * 获取正则表达式匹配结果的matcher，只会返回匹配到的第一个结果。
     *
     * @param str0  待处理字符串
     * @param regex 正则表达式
     * @return 返回matcher
     */
    public static Matcher getMatcher(String str0, String regex) {
        PATTERN = Pattern.compile(regex);
        return PATTERN.matcher(str0);
    }
    //endregion

    //region Repeat String or Char

    /**
     * 将若干个相同的短字符串拼接成一个长字符串。
     *
     * @param str 待拼接的短字符串
     * @param n   重复次数
     * @return 返回长字符串
     */
    public static String repeatString(String str, int n) {
        return repeatString(str, n, "");
    }

    /**
     * 将若干个相同的短字符串拼接成一个长字符串。
     *
     * @param str 待拼接的短字符串
     * @param n   重复次数
     * @param seg 分割符，默认为空
     * @return 返回长字符串
     */
    public static String repeatString(String str, int n, String seg) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < n; i++) {
            sb.append(str).append(seg);
        }
        // 剔除最后一个seg。
        return sb.substring(0, sb.length() - seg.length());
    }

    /**
     * 将若干个相同的短字符串拼接成一个长字符串。
     *
     * @param str 待拼接的短字符串
     * @param n   重复次数
     * @param seg 分割符，默认为空
     * @return 返回长字符串
     */
    public static String repeatString(String str, int n, char seg) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < n; i++) {
            sb.append(str).append(seg);
        }
        // 剔除最后一个seg。
        return sb.substring(0, sb.length() - 1);
    }

    /**
     * 将若干个相同的字符拼接成一个长字符串。
     *
     * @param c 待拼接的字符
     * @param n 重复次数
     * @return 返回长字符串
     */
    public static String repeatChar(char c, int n) {
        return repeatChar(c, n, "");
    }

    /**
     * 将若干个相同的字符拼接成一个长字符串。
     *
     * @param c   待拼接的字符
     * @param n   重复次数
     * @param seg 分割符，默认为空
     * @return 返回长字符串
     */
    public static String repeatChar(char c, int n, String seg) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < n; i++) {
            sb.append(c).append(seg);
        }
        // 剔除最后一个seg。
        return sb.substring(0, sb.length() - seg.length());
    }

    /**
     * 将若干个相同的字符拼接成一个长字符串。
     *
     * @param c   待拼接的字符
     * @param n   重复次数
     * @param seg 分割符，默认为空
     * @return 返回长字符串
     */
    public static String repeatChar(char c, int n, char seg) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < n; i++) {
            sb.append(c).append(seg);
        }
        // 剔除最后一个seg。
        return sb.substring(0, sb.length() - 1);
    }
    //endregion

    /**
     * GBK转UTF-8
     * https://blog.csdn.net/weixin_43641651/article/details/85265550
     *
     * @param gbkStr GBK字符串
     * @return 返回UTF-8编码的字节数组
     */
    public static byte[] gbk2Utf8_Bytes(String gbkStr) {
        int n = gbkStr.length();
        byte[] utfBytes = new byte[3 * n];
        int k = 0;
        for (int i = 0; i < n; i++) {
            int m = gbkStr.charAt(i);
            if (m < 128 && m >= 0) {
                utfBytes[k++] = (byte) m;
                continue;
            }
            utfBytes[k++] = (byte) (0xe0 | (m >> 12));
            utfBytes[k++] = (byte) (0x80 | ((m >> 6) & 0x3f));
            utfBytes[k++] = (byte) (0x80 | (m & 0x3f));
        }
        if (k < utfBytes.length) {
            byte[] tmp = new byte[k];
            System.arraycopy(utfBytes, 0, tmp, 0, k);
            return tmp;
        }
        return utfBytes;
    }

    /**
     * GBK转UTF-8
     * https://blog.csdn.net/weixin_43641651/article/details/85265550
     *
     * @param gbkStr GBK字符串
     * @return 返回UTF-8编码的字符串
     */
    public static String gbk2Utf8(String gbkStr) {
        return new String(gbk2Utf8_Bytes(gbkStr), StandardCharsets.UTF_8);
    }
}
